package com.xuzhiguang.lightnat.server.wrap.config;

import com.xuzhiguang.lightnat.common.message.MessageProcessorFactory;
import com.xuzhiguang.lightnat.common.message.NatMessageTypeEnum;
import com.xuzhiguang.lightnat.server.core.client.DefaultNatClientService;
import com.xuzhiguang.lightnat.server.core.client.NatClientService;
import com.xuzhiguang.lightnat.server.core.server.common.processor.KeepAliveRequestProcessor;
import com.xuzhiguang.lightnat.server.core.server.control.ControlServer;
import com.xuzhiguang.lightnat.server.core.server.control.processor.ConnectResponseProcessor;
import com.xuzhiguang.lightnat.server.core.server.proxy.ProxyServer;
import com.xuzhiguang.lightnat.server.core.server.transfer.TransferServer;
import com.xuzhiguang.lightnat.server.core.server.transfer.processor.ConnectRequestProcessor;
import com.xuzhiguang.lightnat.server.core.server.transfer.processor.DisconnectRequestProcessor;
import com.xuzhiguang.lightnat.server.core.server.transfer.processor.TransferRequestProcessor;
import com.xuzhiguang.lightnat.server.wrap.manager.NatClientManager;
import com.xuzhiguang.lightnat.server.wrap.properties.ServerProperties;
import com.xuzhiguang.lightnat.server.wrap.server.ServerBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties({ServerProperties.class})
public class NatServerConfig {

    @Bean
    public NatClientService natClientService() {
        return new DefaultNatClientService();
    }

    @Bean
    public NatClientManager natClientManager(NatClientService natClientService, ProxyServer proxyServer) {
        return new NatClientManager(natClientService, proxyServer);
    }

    @Bean
    public ProxyServer proxyServer(NatClientService natClientService) {
        return new ProxyServer.Builder()
                .natClientService(natClientService)
                .build();
    }

    @Bean
    public TransferServer transferServer(NatClientService natClientService, ServerProperties serverProperties) {

        MessageProcessorFactory messageProcessorFactory
                = new MessageProcessorFactory.Builder()
                .addProcessor(NatMessageTypeEnum.CONNECT_REQUEST.getType(), new ConnectRequestProcessor())
                .addProcessor(NatMessageTypeEnum.DISCONNECT_REQUEST.getType(), new DisconnectRequestProcessor())
                .addProcessor(NatMessageTypeEnum.TRANSFER.getType(), new TransferRequestProcessor())
                .addProcessor(NatMessageTypeEnum.KEEP_ALIVE_REQUEST.getType(), new KeepAliveRequestProcessor())
                .build();

        return new TransferServer.Builder()
                .transferServerProperties(serverProperties)
                .natClientService(natClientService)
                .messageProcessorFactory(messageProcessorFactory)
                .build();
    }

    @Bean
    public ControlServer controlServer(NatClientService natClientService, ServerProperties serverProperties) {

        MessageProcessorFactory messageProcessorFactory
                = new MessageProcessorFactory.Builder()
                .addProcessor(NatMessageTypeEnum.KEEP_ALIVE_REQUEST.getType(), new KeepAliveRequestProcessor())
                .addProcessor(NatMessageTypeEnum.CONNECT_RESPONSE.getType(), new ConnectResponseProcessor(natClientService))
                .build();

        return new ControlServer.Builder()
                .natClientService(natClientService)
                .controlServerProperties(serverProperties)
                .messageProcessorFactory(messageProcessorFactory)
                .build();
    }

    @Bean
    public ServerBean proxyServerBean(ProxyServer proxyServer) {
        return new ServerBean(proxyServer);
    }

    @Bean
    public ServerBean transferServerBean(TransferServer transferServer) {
        return new ServerBean(transferServer);
    }

    @Bean
    public ServerBean controlServerBean(ControlServer controlServer) {
        return new ServerBean(controlServer);
    }
}
